package de.fuberlin.inf.alp3.ue06;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;

public class LinkedList<T> implements Foldable<T>, List<T> {
    
    private class Cell {
        T value;
        Cell next;
        public Cell(T value){
            this.value = value;
            this.next = null;
        }
    }
    private Cell first;
    private Cell last;

    @Override
    public T fold(BinaryOperation<T> op, T init) {
        T result = init;
        for (T item : this)
            result = op.call(item, result);
        return result;
    }
    
    public void append(T value) {
        this.add(value);
    }

    @Override
    public boolean add(T value) {
        if (isEmpty())
            this.first = this.last = new Cell(value);
        else
            this.last = this.last.next = new Cell(value);
        return true;
    }

    @Override
    public void add(int index, T value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addAll(Collection<? extends T> values) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> values) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        this.first = this.last = null;
    }

    @Override
    public boolean contains(Object arg0) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean containsAll(Collection<?> arg0) {
        throw new UnsupportedOperationException();
    }

    @Override
    public T get(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int indexOf(Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isEmpty() {
        return (this.first == null);
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            Cell current = first;
            public boolean hasNext() {
                return current != null;
            }
            public T next() throws NoSuchElementException {
                if (current == null )
                    throw new NoSuchElementException();
                T x = current.value;
                current = current.next;
                return x;
            }
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public int lastIndexOf(Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public ListIterator<T> listIterator() {
        throw new UnsupportedOperationException();
    }

    @Override
    public ListIterator<T> listIterator(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean remove(Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public T remove(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection<?> arg0) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> arg0) {
        throw new UnsupportedOperationException();
    }

    @Override
    public T set(int index, T value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public int size() {
        int result = 0;
        Cell current = this.first;
        while (current != null) {
            current = current.next;
            result++;
        }
        return result;
    }

    @Override
    public List<T> subList(int arg0, int arg1) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object[] toArray() {
        throw new UnsupportedOperationException();
    }

    @Override
    public <E> E[] toArray(E[] arg0) {
        throw new UnsupportedOperationException();
    }

}
